﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;

using System.Drawing;
using System.Windows.Forms;

namespace Weazel.Gezel.Simulator.Reference.IpBlocks
{
	[IpBlockAttribute("weazelpongdisplay")]
	public class WeazelPongDisplay : AbstractIpBlock
	{
		private const int LeftPaddleYCanReadPinNumber		= 0;
		private const int LeftPaddleYPinNumber					= 1;
		private const int LeftPaddleYDoReadPinNumber		= 8;

		private const int RightPaddleYCanReadPinNumber	= 2;
    private const int RightPaddleYPinNumber					= 3;		
		private const int RightPaddleYDoReadPinNumber		= 9;

		private const int BallXCanReadPinNumber					= 4;
		private const int BallXPinNumber								= 5;
		private const int BallXDoReadPinNumber					= 10;

		private const int BallYCanReadPinNumber					=	6;
		private const int BallYPinNumber								= 7;
		private const int BallYDoReadPinNumber					= 11;

    private int fieldHeight = -1;
    private int fieldWidth = -1;
    
    PongDisplayControl displayControl;

		public WeazelPongDisplay(string name)
      : base(name)
    {      
    }

    private void RunThread()
    {
      Form form = new Form();

      displayControl = new PongDisplayControl();
      displayControl.Dock = DockStyle.Fill;
      
      form.Controls.Add(displayControl);
      form.ActiveControl = displayControl;
      form.ClientSize = new Size(fieldHeight, fieldWidth);
      form.ShowDialog();
    }


		
		//public override void Evaluate(long g)
		//{
		//  //throw new NotImplementedException();
		//}

    /// <summary>
    /// Note, if parameters are not integers, or negative, 
    /// simulation will not run properly. It is hard to proper
    /// validation of ipblocks with the current lack of design 
    /// anyways.
    /// </summary>
    /// <param name="_name"></param>
    public override void SetParameter(string _name)
    {
      string field = _name.Substring(0, _name.IndexOf('='));
      string value = _name.Substring(_name.IndexOf('=') + 1);

      if (field == "width")
        fieldWidth = int.Parse(value);
      else if (field == "height")
        fieldHeight = int.Parse(value);

      if (fieldHeight != -1 && fieldWidth != -1)
      {
        Thread worker = new Thread(new ThreadStart(RunThread));
        worker.IsBackground = true;
        worker.Start();
      }
    }

    public override bool CheckTerminal(int n, string tname, IoDirection dir)
    {
			Console.WriteLine("n: {0} \t dir: {2} \t tname: {1}", n, tname, dir);
      switch (n)
      {

				case LeftPaddleYCanReadPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Input && tname == "position_left_paddle_y_can_read");
				case LeftPaddleYPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Input && tname == "position_left_paddle_y");
				case LeftPaddleYDoReadPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Output && tname == "position_left_paddle_y_do_read");

				case RightPaddleYCanReadPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Input && tname == "position_right_paddle_y_can_read");
				case RightPaddleYPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Input && tname == "position_right_paddle_y");
				case RightPaddleYDoReadPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Output && tname == "position_right_paddle_y_do_read");

				case BallXCanReadPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Input && tname == "position_ball_x_can_read");
        case BallXPinNumber:
          return (dir == AbstractIpBlock.IoDirection.Input && tname == "position_ball_x");
				case BallXDoReadPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Output && tname == "position_ball_x_do_read");

				case BallYCanReadPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Input && tname == "position_ball_y_can_read");
        case BallYPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Input && tname == "position_ball_y");				
				case BallYDoReadPinNumber:
					return (dir == AbstractIpBlock.IoDirection.Output && tname == "position_ball_y_do_read");

        default:
          throw new NotSupportedException("CheckTerminal() unknown 'n' value (" + n + ")");
      }
    }

    public override void Run()
    {
      try
      {
				
				int ballXCanRead				= ioValues[BallXCanReadPinNumber].ToInt(); 
        int ballX								= ioValues[BallXPinNumber].ToInt();
			
				int ballYCanRead				= ioValues[BallYCanReadPinNumber].ToInt();
        int ballY								= ioValues[BallYPinNumber].ToInt();

        int leftPaddleYCanRead	= ioValues[LeftPaddleYCanReadPinNumber].ToInt();
				int leftPaddleY					= ioValues[LeftPaddleYPinNumber].ToInt();

        int rightPaddleYCanRead	= ioValues[RightPaddleYCanReadPinNumber].ToInt();
				int rightPaddleY				= ioValues[RightPaddleYPinNumber].ToInt();

				//System.Diagnostics.Trace.Assert(ballXCanRead == ballYCanRead == leftPaddleYCanRead == rightPaddleYCanRead);

				if (ballXCanRead == 1)
					ioValues[BallXDoReadPinNumber].Assign(1);
				else
					ioValues[BallXDoReadPinNumber].Assign(0);

				if (ballYCanRead == 1)
					ioValues[BallYDoReadPinNumber].Assign(1);
				else
					ioValues[BallYDoReadPinNumber].Assign(0);

				if (leftPaddleYCanRead == 1)
					ioValues[LeftPaddleYDoReadPinNumber].Assign(1);
				else
					ioValues[LeftPaddleYDoReadPinNumber].Assign(0);

				if (rightPaddleYCanRead == 1)
					ioValues[RightPaddleYDoReadPinNumber].Assign(1);
				else
					ioValues[RightPaddleYDoReadPinNumber].Assign(0);

				if (ballXCanRead == 1 && leftPaddleYCanRead == 1 && rightPaddleYCanRead == 1)
				{
					//Console.WriteLine("ball_x: {0} ball_y: {1} left_padle_y: {2} right_paddle_y: {3}",
					//  ballX,
					//  ballY,
					//  leftPaddleY,
					//  rightPaddleY
					//);

					displayControl.Update(ballX, ballY, 10, leftPaddleY, 70, rightPaddleY);
				}
				

        System.Threading.Thread.Sleep(20);

        //Console.WriteLine("ball position ({0}, {1})", ballX, ballY);
      }
      catch (Exception e)
      {
        String message = e.GetType().ToString() + " " +
          e.Message + " trace: \n" + e.StackTrace;

        System.Windows.Forms.MessageBox.Show(message);
      }
    }
  }
}
